package flags

import (
	"flag"
	"os"
	"strconv"
	"strings"
)

var (
	flagmap map[string]*FlagModel // 存储命令行参数的映射
	envmap  map[string]*FlagModel // 存储环境变量的映射
)

func init() {
	flagmap = make(map[string]*FlagModel) // 初始化命令行参数映射
	envmap = make(map[string]*FlagModel)  // 初始化环境变量映射
}

// FlagModel 表示一个参数模型
type FlagModel struct {
	FlagName string // 命令行参数名
	EnvName  string // 环境变量名
	Usage    string // 参数描述
	Val      string // 参数值
	Default  string // 默认值
}

// 设置要读的参数
// 根据命令行参数名和环境变量名注册参数，并存储到映射中
func SetFlag(flagname, envname, note, def string) {
	m := &FlagModel{
		FlagName: flagname,
		EnvName:  envname,
		Usage:    note,
		Default:  def,
		Val:      def,
	}
	if m.FlagName != "" { // 如果命令行参数名不为空
		// 将参数添加到命令行参数映射，并注册到 flag 包中
		flagmap[m.FlagName] = m                                // 添加到命令行参数映射
		flag.StringVar(&m.Val, m.FlagName, m.Default, m.Usage) // 注册命令行参数
	}
	if m.EnvName != "" { // 如果环境变量名不为空
		// 将参数添加到环境变量映射
		envmap[m.EnvName] = m // 添加到环境变量映射
	}
}

// 解析参数
// 优先从环境变量中读取值，然后解析命令行参数
func Parse() {
	for _, m := range envmap {
		if v, ok := os.LookupEnv(m.EnvName); ok { // 从环境变量中读取值
			// 如果环境变量存在，将其值赋给参数
			m.Val = v
		}
	}
	flag.Parse() // 解析命令行参数
}

// 获取整数类型的命令行参数值
// 如果参数不存在，返回默认值 0
func GetFlagByInt(name string) int {
	if m, ok := flagmap[name]; ok {
		res, _ := strconv.Atoi(m.Val)
		return res
	}
	return 0
}

// 获取无符号整数类型的命令行参数值
// 如果参数不存在，返回默认值 0
func GetFlagByUint(name string) uint {
	if m, ok := flagmap[name]; ok {
		res, _ := strconv.ParseUint(m.Val, 10, 64)
		return uint(res)
	}
	return 0
}

// 获取字符串类型的命令行参数值
// 如果参数不存在，返回默认值 ""
func GetFlagByString(name string) string {
	if m, ok := flagmap[name]; ok {
		return m.Val
	}
	return ""
}

// 获取浮点数类型的命令行参数值
// 如果参数不存在，返回默认值 0
func GetFlagByFloat64(name string) float64 {
	if m, ok := flagmap[name]; ok {
		res, _ := strconv.ParseFloat(m.Val, 64)
		return res
	}
	return 0
}

// 获取切片类型的命令行参数值
// 如果参数不存在，返回空切片
func GetFlagBySlice(name string) []string {
	if m, ok := flagmap[name]; ok {
		m.Val = strings.ReplaceAll(m.Val, " ", ",") // 替换空格为逗号
		return strings.Split(m.Val, ",")            // 按逗号分割为切片
	}
	return []string{}
}

// 获取布尔类型的命令行参数值
// 如果参数不存在，返回默认值 false
func GetFlagByBool(name string) bool {
	if m, ok := flagmap[name]; ok {
		res, _ := strconv.ParseBool(m.Val)
		return res
	}
	return false
}

// 获取整数类型的环境变量值
// 如果环境变量不存在，返回默认值 0
func GetEnvByInt(name string) int {
	if m, ok := envmap[name]; ok {
		res, _ := strconv.Atoi(m.Val)
		return res
	}
	return 0
}

// 获取字符串类型的环境变量值
// 如果环境变量不存在，返回默认值 ""
func GetEnvByString(name string) string {
	if m, ok := envmap[name]; ok {
		return m.Val
	}
	return ""
}

// 获取浮点数类型的环境变量值
// 如果环境变量不存在，返回默认值 0
func GetEnvByFloat64(name string) float64 {
	if m, ok := envmap[name]; ok {
		res, _ := strconv.ParseFloat(m.Val, 64)
		return res
	}
	return 0
}

// 获取切片类型的环境变量值
// 如果环境变量不存在，返回空切片
func GetEnvBySlice(name string) []string {
	if m, ok := envmap[name]; ok {
		m.Val = strings.ReplaceAll(m.Val, " ", ",") // 替换空格为逗号
		return strings.Split(m.Val, ",")            // 按逗号分割为切片
	}
	return []string{}
}

// 获取布尔类型的环境变量值
// 如果环境变量不存在，返回默认值 false
func GetEnvByBool(name string) bool {
	if m, ok := envmap[name]; ok {
		res, _ := strconv.ParseBool(m.Val)
		return res
	}
	return false
}
